# encoding: utf-8
# 项目名称： day02
# @File  : account.py
# @Author: sun hao
# @Desc :  用户登录模块
# @Date  :   16:04 2024/10/02

from django import forms
from django.shortcuts import HttpResponse, render, redirect
from app01 import models
from app01.utils.encrypt import md5
from app01.utils.layUI import LayUiForm
from app01.utils.code import check_code
from io import BytesIO

class LoginForm(LayUiForm):
    # 这里我直接写个类，让LoginForm 去继承一下
    username = forms.CharField(
        label="用户名",
        widget=forms.TextInput(
            attrs={
                "lay-affix": "clear",
            }
        ),
        required=True,
        error_messages={
            'required': '请输入用户名',
        }
    )
    password = forms.CharField(
        label="密码",
        widget=forms.PasswordInput(
            render_value=True,  # 记住密码页面数据回显，当用户密码校验不通过时
            attrs={
                "lay-affix": "eye",
            }
        ),
        required=True,
        error_messages={
            'required': '请输入密码',
        }
    )
    code = forms.CharField(
        label="验证码",
        widget=forms.TextInput(
            attrs={
                "lay-affix": "clear",
            }
        ),
        required=True,
        error_messages={
            'required': '请填写验证码',
        }
    )
    def clean_password(self):
        # 使用钩子方法，拿到输入的密码，md5 加密一下，这样在后面的步骤中可以直接去库里校验匹配了
        pwd = self.cleaned_data.get("password")
        return md5(pwd)


def login(request):
    """
    用户登录
    """
    if request.method == 'GET':
        form = LoginForm()
        return render(request, 'login/login.html', {"form": form})
    print(request.POST)
    form = LoginForm(data=request.POST)
    if form.is_valid():
        """
            数据校验通过,可以拿到输入的用户名密码
            { username:"xxx",password:"xxx" }
            因为我这里使用的Form 只能使用form.cleaned_data
            如果是ModelForm,就可以使用form.save
        """
        # print(form.cleaned_data)
        # 验证码的校验比较,统一转大写比较
        user_input_code = form.cleaned_data.pop('code') # 用户提交过来的code
        session_image_code = request.session.get('image_code',"") # 服务器事先存储下的code，可能会为空
        if session_image_code.upper() != user_input_code.upper():
            form.errors.clear()  # 清除上一次的错误信息
            form.add_error("code", "验证码错误")
            return render(request, 'login/login.html', {"form": form})

        # 这里为什么使用pop，来干掉code字段呢，
        # Admin 表中没有code字段，如果不去掉，code就会参与sql的检索，会导致程序崩溃
        # 拿到用户名密码，去库里校验
        search_dict = form.cleaned_data  # 这里 我接收到的字段名跟库里的表字段名一样，可以直接这样写
        login_row = models.Admin.objects.filter(**search_dict).first()
        if not login_row:
            # 没有这个账号密码
            form.errors.clear()  # 清除上一次的错误信息
            form.add_error("username", "用户名或密码错误")
            form.add_error("password", "用户名或密码错误")
            return render(request, 'login/login.html', {"form": form})
        # 用户名，密码匹配上了
        # 网站生成随机字符串，写到用户浏览器的cookie中，在写入到session中
        # 页面刷一下，或者 请求一个接口。浏览器可以看到cookie那里有个sessionid 与 库里 django_session 是对应的
        request.session["login_info"] = {"id": login_row.id, "name": login_row.username}
        request.session.set_expiry(60*60*24*7) # 重新设置有效时间7天有效。为啥要这么做？之前设置图片验证码60秒有效，需要覆盖掉。
        return redirect("/admin/list/")
        # return  HttpResponse("登录成功")
    return render(request, 'login/login.html', {"form": form})


def logout(request):
    """
        用户注销
    """
    request.session.clear()
    return redirect("/login/")


# def image_code(request):
#     """
#         图片验证码
#     """
#     img,code_str = check_code()
#     # 把验证码写到session中，我们在登录接口那边拿到 账号密码后，校验验证码大小写对不对
#     request.session["image_code"] = code_str
#     request.session.set_expiry = 60 # 验证码60秒以内有效
#     print("图片验证码："+code_str)
#     # 3. img 写入内存(Python3)
#     stream = BytesIO()
#     img.save(stream, 'png')


#     return HttpResponse(stream.getvalue())


def image_code(request):
    """
    图片验证码
    """
    img, code_str = check_code()
    # 把验证码写到session中，我们在登录接口那边拿到 账号密码后，校验验证码大小写对不对
    request.session["image_code"] = code_str
    request.session.set_expiry(60)  # 验证码60秒以内有效
    print("图片验证码：" + code_str)
    
    # 使用上下文管理器来确保 BytesIO 正确关闭
    with BytesIO() as stream:
        img.save(stream, 'png')
        return HttpResponse(stream.getvalue(), content_type='image/png')